package dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import utility.NameValueList;
import utility.StringUtils;

public class BaseDaoHibernate<T> {

    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(BaseDaoHibernate.class.getName());
    
    @SuppressWarnings("unchecked")
    protected Class domainClass;

    @Autowired
    protected SessionFactory sessionFactory;
    @SuppressWarnings("unchecked")
    public BaseDaoHibernate() {
        this.domainClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
    
    public boolean save(T domain) {
        
        boolean success = false;
        try {
            sessionFactory.getCurrentSession().saveOrUpdate(domain);
            success = true;  
            
        } catch (RuntimeException e) { 
            log.error("save failed", e);
            java.util.logging.Logger.getLogger(BaseDaoHibernate.class.getName()).log(java.util.logging.Level.SEVERE, null, e);
            success = false; 
        }
        
        finally {}
        return success;
    }

    @SuppressWarnings("unchecked")
    public T getById(Long id) {
        return (T) sessionFactory.getCurrentSession().get(domainClass, id);
    }
    
    @SuppressWarnings("unchecked")
    public T getById(int id) {
        return (T) sessionFactory.getCurrentSession().get(domainClass, id);
    }
    
    @SuppressWarnings("unchecked")
    public T getByKode(String fieldKode, String fieldValue) {
        return (T) sessionFactory.getCurrentSession().createQuery(
            "from " + domainClass.getName() + " x "
            .concat(" where lower(").concat(fieldKode)
            .concat(") = lower(").concat(StringUtils.fmtSQLString(fieldValue)).concat(")"))
            .uniqueResult();
    }
    
    @SuppressWarnings("unchecked")
    public Object getFieldValue(String fieldName, int id) {
        return (Object) sessionFactory.getCurrentSession().createQuery(
            "select x."+fieldName+" from " + domainClass.getName() + " x "+
            "where x.id = "+id)
            .uniqueResult();
    }
    
    @SuppressWarnings("unchecked")
    public Object getFieldValue(String fieldName, long id) {
        return (Object) sessionFactory.getCurrentSession().createQuery(
            "select x."+fieldName+" from " + domainClass.getName() + " x "+
            "where x.id = "+id)
            .uniqueResult();
    }
    
    @SuppressWarnings("unchecked")
    public T getByCustomQuery(String completeQuery) {
        return (T) sessionFactory.getCurrentSession().createQuery(completeQuery)
            .uniqueResult();
    }
        
    public boolean delete(T domain) {
        boolean success = false;
        try {
            sessionFactory.getCurrentSession().delete(domain);
            success = true;  
            
        } catch (RuntimeException e) { 
            log.error("save failed", e);
            success = false; 
        }
        
        finally {}
        return success;
    }
    
    @SuppressWarnings("unchecked")
    public Long count() {
        return (Long) sessionFactory.getCurrentSession().createQuery(
                "select count(*) from " + domainClass.getName() + " x").uniqueResult();
    }
    
    @SuppressWarnings("unchecked")
    public Long count(String completedQuery) {
        return (Long) sessionFactory.getCurrentSession().createQuery(completedQuery).uniqueResult();
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        return sessionFactory.getCurrentSession().createQuery("from " + domainClass.getName())
                .list();
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getAll(int start, int num) {
        return sessionFactory.getCurrentSession().createQuery("from " + domainClass.getName())
                .setFirstResult(start).setMaxResults(num)
                .list();
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getAll(int start, int num, String params, String orderBy) {
        if (params == null) {params = "";}
        if (orderBy == null) {orderBy = "";}
        params = " ".concat(params);
        orderBy = " ".concat(orderBy);
        
        return sessionFactory.getCurrentSession().createQuery(
                "from ".concat(domainClass.getName()).concat(params).concat(orderBy))
                .setFirstResult(start).setMaxResults(num)
               // .setCacheable(true)
                .list();
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getAll(int start, int num, String completedQuery) {
        return sessionFactory.getCurrentSession().createQuery(completedQuery)
                .setFirstResult(start).setMaxResults(num)
               // .setCacheable(true)
                .list();
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getAll(String completedQuery) {
        //ngirim sql yg sudah lengkap with where etc...
        return sessionFactory.getCurrentSession().createQuery(completedQuery).list();
    }
    
    
    @SuppressWarnings("unchecked")
    public T getByParam(String param) {
        return (T) sessionFactory.getCurrentSession().createQuery(
            "from " + domainClass.getName() + " x "
            .concat(" where ").concat(param))
            .uniqueResult();
    }
    
    public List<NameValueList> getNameValueList(String completedQuery) {
        List<NameValueList> nameValueList;
        try {
            nameValueList = sessionFactory.getCurrentSession().createQuery(completedQuery)
                    .setResultTransformer(Transformers.aliasToBean(NameValueList.class))
                    .list();

        } catch (Exception ex) { throw new RuntimeException(ex); }
        return nameValueList;
    }
    
}
